package vip.aster.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import vip.aster.common.constant.CacheConstants;
import vip.aster.common.utils.CacheUtils;
import vip.aster.common.utils.ExcelUtils;
import vip.aster.common.utils.ExceptionUtils;
import vip.aster.common.utils.PageInfo;
import vip.aster.framework.i18n.MessageUtils;
import vip.aster.framework.log.dto.OperateLogDTO;
import vip.aster.system.entity.SysLogOperate;
import vip.aster.system.mapper.SysLogOperateMapper;
import vip.aster.system.query.SysLogOperateQuery;
import vip.aster.system.service.SysLogOperateService;
import vip.aster.system.vo.SysLogOperateVO;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 操作日志 服务实现类
 * </p>
 *
 * @author Aster
 * @since 2023-11-28 10:36
 */
@Service
@AllArgsConstructor
public class SysLogOperateServiceImpl extends ServiceImpl<SysLogOperateMapper, SysLogOperate> implements SysLogOperateService {
    private SysLogOperateMapper sysLogOperateMapper;

    @PostConstruct
    public void saveOperateLog() {
        ScheduledExecutorService scheduledService = ThreadUtil.createScheduledExecutor(1);
        // 每隔30秒钟，执行一次
        scheduledService.scheduleWithFixedDelay(() -> {
            try {
                // 每次插入10条
                int count = 10;
                for (int i = 0; i < count; i++) {
                    OperateLogDTO log = (OperateLogDTO) CacheUtils.rightPop(CacheConstants.SYS_LOG_KEY, CacheConstants.OPERATE_LOG_KEY);
                    if (log == null) {
                        return;
                    }

                    SysLogOperate entity = BeanUtil.copyProperties(log, SysLogOperate.class);
                    sysLogOperateMapper.insert(entity);
                }
            } catch (Exception e) {
                log.error("SysLogOperateServiceImpl.saveLog Error：" + ExceptionUtils.getExceptionMessage(e));
            }
        }, 1, 30, TimeUnit.SECONDS);
    }

    @Override
    public PageInfo<SysLogOperateVO> pageList(SysLogOperateQuery query) {
        Page<SysLogOperate> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<SysLogOperate> pageList = sysLogOperateMapper.selectPage(page, getWrapper(query));
        return new PageInfo<>(SysLogOperateVO.convertList(pageList.getRecords()), pageList.getTotal());
    }

    @Override
    public void export(SysLogOperateQuery query) {
        List<SysLogOperate> list = this.list(getWrapper(query));
        List<SysLogOperateVO> operateList = SysLogOperateVO.convertList(list);
        // 写到浏览器打开
        String excelName = "operate_log_" + LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DatePattern.NORM_DATE_PATTERN);
        String sheetName = MessageUtils.message("log.operate.sheetName");
        ExcelUtils.excelExport(SysLogOperateVO.class, excelName, sheetName, operateList);
    }

    private LambdaQueryWrapper<SysLogOperate> getWrapper(SysLogOperateQuery query) {
        LambdaQueryWrapper<SysLogOperate> wrapper = Wrappers.lambdaQuery();

        wrapper.like(StrUtil.isNotBlank(query.getUsername()), SysLogOperate::getUsername, query.getUsername());
        wrapper.eq(StrUtil.isNotBlank(query.getBusinessType()), SysLogOperate::getBusinessType, query.getBusinessType());
        if (StrUtil.isNotBlank(query.getStartTime())) {
            wrapper.ge(SysLogOperate::getOperTime, LocalDateTimeUtil.parse(query.getStartTime(), DatePattern.NORM_DATETIME_PATTERN));
        }
        if (StrUtil.isNotBlank(query.getEndTime())) {
            wrapper.le(SysLogOperate::getOperTime, LocalDateTimeUtil.parse(query.getEndTime(), DatePattern.NORM_DATETIME_PATTERN));
        }
        wrapper.orderByDesc(SysLogOperate::getOperTime);

        return wrapper;
    }
}
